#include "app_bt.h"
#include <string.h>
#include "app_common.h"
#include "log.h"
#include <fcntl.h>
#include <unistd.h>
#include "app_serial.h"

/**
 * @brief 读后预处理
 * // 之前  echo -n -e "\xf9\xf9\x01\x01\x33\x33" >>test_dev_file
         echo -n -e "\x00\x00\x00\xff\xf1\xdd" >>test_dev_file
        echo -n -e "\x07\x23\x23\xff\xff\x41" >>test_dev_file
        echo -n -e "\x42\x43\x88\x00\x99\x41" >>test_dev_file
        //  之后 01 02 03 23 23 41 42 43
   //0 准备一个缓冲区
   //1 把新到的数据写入缓冲区
   //2 针对n缓冲区进行检查 是否有整帧的数据
   //3 寻找帧头
   //4 如果找到帧头
   //  4.1 删除帧头以前的数据（此时帧头处于缓冲区开头）
   //  4.2 判断目前缓冲区是否达到最小一帧数据的长度（8个字节）
   //  4.3 取出长度帧头进行判断，判断之后的数据长度是否达到长度帧头的值
   //  如果满足条件
   // 5 提取数据 提取 id msg  拼接为字节数组结构
   // 6 把一整帧数据从缓冲区中删除
   // 7 减去长度
   // 8 返回新数据长度

 */

static char post_read_buffer[100];
static int buff_data_len = 0;
static char read_header[2] = {0xf1, 0xdd};

/**
 * @brief 删除缓冲区中帧头之前的数据
 * @param rm_idx 删除多少字节的数据
 */
static void rm_data_from_buff(int rm_size)
{
    memmove(post_read_buffer, post_read_buffer + rm_size, buff_data_len - rm_size);
    buff_data_len -= rm_size;
}

static int app_bt_post_read(char *data, int data_size)
{
    // 0 准备一个缓冲区
    // 打印当前缓冲区
    log_info("buff_data_len:%d", buff_data_len);
    app_common_bytes_print(post_read_buffer, buff_data_len);
    // 1 把新到的数据写入缓冲区
    memcpy(post_read_buffer + buff_data_len, data, data_size);
    buff_data_len += data_size;

    // 2 针对 缓冲区进行检查 是否有整帧的数据
    // 3 寻找帧头
    for (int i = 0; i < buff_data_len; i++)
    {
        if (post_read_buffer[i] == read_header[0] && post_read_buffer[i + 1] == read_header[1])
        {
            // 4 如果找到帧头
            //   4.1 删除帧头以前的数据（此时帧头处于缓冲区开头）
            rm_data_from_buff(i);
            //  4.2 判断目前缓冲区是否达到最小一帧数据的长度（8个字节）
            if (buff_data_len < 8)
            {
                return 0;
            }
            //  4.3 取出长度帧头进行判断，判断之后的数据长度是否达到长度帧头的值
            int post_expect_len = post_read_buffer[2];
            if (buff_data_len >= post_expect_len + 3)
            { //  如果满足条件
                // 5 提取数据 提取 id msg  拼接为字节数组结构
                char id[2];
                memcpy(id, post_read_buffer + 3, 2);
                int msg_len = post_expect_len - 4; // msg长度 = 预期长度-4（两个id）
                char msg[msg_len];
                memcpy(msg, post_read_buffer + 7, msg_len);

                // 6 把一整帧数据从缓冲区中删除
                data[0] = 0x01;                     // 蓝牙连接类型
                data[1] = 2;                        // id长度
                data[2] = msg_len;                  // 数据长度
                memcpy(data + 3, id, 2);            // id
                memcpy(data + 3 + 2, msg, msg_len); // msg数据
                // 7 减去长度
                rm_data_from_buff(post_expect_len + 3); // 帧头+之后的长度
                                                        // 8 返回新数据长度
                return 3 + 2 + msg_len;
            }
        }
    }
    return 0;
}

/**
 * @brief 写前预处理
 * // 之前  连接类型 id长度  数据长度   id  数据
 * // 之后  41 54 2b 4d 45 53 48 00  id  数据  0d 0a
 */
static char write_header[8] = {0x41, 0x54, 0x2b, 0x4d, 0x45, 0x53, 0x48, 0x00};
static char write_tailer[2] = {0x0d, 0x0a};

int app_bt_pre_write(char *data, int data_size)
{
    char buff[100];
    memcpy(buff, write_header, 8); // 头
    char data_id_msg[100];
    memcpy(data_id_msg, data + 3, data_size - 3); // 提取
    memcpy(buff + 8, data_id_msg, data_size - 3); // 中间部分

    memcpy(buff + 8 + data_size - 3, write_tailer, 2); // 结尾

    int len = 8 + (data_size - 3) + 2; // 转换后总长度
    memcpy(data, buff, len);           // 覆盖原始数据

    return len;
}

int waitack(app_device_t *device)
{
    usleep(50 * 1000);
    char res[4];
    read(device->dev_fd, res, 4);
    if (memcmp(res, "OK\r\n",4) == 0)
    {
        return 0;
    }
    return -1;
}

/**
 *  @brief 蓝牙测试
 */
int app_bt_status(app_device_t *device)
{
    char cmd[4] = "AT\r\n";
    write(device->dev_fd, cmd, 4);
    return waitack(device);
}

/**
 *  @brief 蓝牙复位
 */
int app_bt_reset(app_device_t *device)
{
    char cmd[10] = "AT+RESET\r\n";
    write(device->dev_fd, cmd, 10);
    return 0;
}
/**
 * @brief 设置波特率
 */
int app_bt_set_baudrate(app_device_t *device, BT_BAUD_RATE baudrate)
{
    char cmd[20];
    sprintf(cmd, "AT+BAUD%c\r\n", baudrate);
    write(device->dev_fd, cmd, strlen(cmd));
    usleep(50 * 1000);
    return 0;
}

/**
 * @brief 设置网络名称
 */
int app_bt_set_netname(app_device_t *device, char *name)
{
    char cmd[40];
    sprintf(cmd, "AT+NAME%s\r\n", name);
    write(device->dev_fd, cmd, strlen(cmd));
    usleep(50 * 1000);
    return 0;
}

/**
 * @brief 设置网络id
 */
int app_bt_set_netid(app_device_t *device, char *netid)
{
    char cmd[40];
    sprintf(cmd, "AT+NETID%s\r\n", netid);
    write(device->dev_fd, cmd, strlen(cmd));
    usleep(50 * 1000);
    return 0;
}

/**
 * @brief 设置短地址
 */
int app_bt_set_maddr(app_device_t *device, char *maddr)
{
    char cmd[40];
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    write(device->dev_fd, cmd, strlen(cmd));
    usleep(50 * 1000);
    return 0;
}

/**
 * @brief 默认蓝牙模块的初始配置
    //1 保证波特率一直
    //1.1  因为要进行 测试所以要设为非阻塞模式
    //1.2  进行测试 ATstatus
    //2  如果测试失败 调平波特率  主控115200  蓝牙9600
    // 2.1  波特率不一致
     // 2.2 主控的降为9600
     // 2.3  再次测试 如果还不通过 报错 检测配线 蓝牙模块有问题
    //  2.4  如果通过  发送at指令让蓝牙模块变为115200
     // 2.5  重启蓝牙模块  执行atreset 操作,蓝牙重启需要时间建议等待1秒
     // 2.6  主控改为115200
      // 2.7  再次测试 如果通过  则设置成功  不通过 蓝牙模块有问题
    //3  设置其他值： 网络名 网络id 网络短地址
     //4    改为阻塞模式
 */
int app_bt_config_default(app_device_t *device)
{
    // 1 保证波特率一直
    // 1.1  因为要进行 测试所以要设为非阻塞模式
    app_serial_isblock(device, 0);
    tcflush(device->dev_fd, TCIOFLUSH);
    // 1.2  进行测试 ATstatus
    if (app_bt_status(device) == -1)
    {
        log_info("主控和蓝牙波特率不一致，进行调解");
        // 2  如果测试失败 调平波特率  主控115200  蓝牙9600
        //  2.1  波特率不一致
        //  2.2 主控的降为9600
        app_serial_baud(device, BR_9600);
        tcflush(device->dev_fd, TCIOFLUSH);

        // 2.3  再次测试 如果还不通过 报错 检测配线 蓝牙模块有问题
        if (app_bt_status(device) == -1)
        {
            log_error("蓝牙模块配置失败 9600,检查配线,蓝牙模块有问题");
            return -1;
        }
        log_info("主控和蓝牙波特率均为9600 "); 
        //  2.4  如果通过  发送at指令让蓝牙模块变为115200
        app_bt_set_baudrate(device, BT_BAUD_115200);
        // 2.5  重启蓝牙模块  执行atreset 操作,蓝牙重启需要时间建议等待1秒
        app_bt_reset(device);
        sleep(1);
        // 2.6  主控改为115200
        app_serial_baud(device, BR_115200);
        tcflush(device->dev_fd, TCIOFLUSH);
        // 2.7  再次测试 如果通过  则设置成功  不通过 蓝牙模块有问题
        if (app_bt_status(device) == -1)
        {
            log_error("蓝牙模块再次测试失败115200 ,检查配线,蓝牙模块有问题");
            return -1;
        }
    }
    log_info("主控和蓝牙波特率均为115200 "); 
    // 3  设置其他值： 网络名 网络id 网络短地址
    app_bt_set_netname(device, "atguigu");
    app_bt_set_netid(device, "1234"); // 组网id  每个组一个
    app_bt_set_maddr(device, "0077"); // 网关的短地址 在一个组网内部不能重复 每个设备一个

    // 4    改为阻塞模式
    app_serial_isblock(device, 1);
    tcflush(device->dev_fd, TCIOFLUSH);
    return 0;
}

/**
 * @brief 为设备进行初始化配置
 * //1 配置 读后预处理
 * //2 配置 写前预处理
 * //3 配置相关的蓝牙参数  波特率 、 网络id  网络短地址  网络名
 */
int app_bt_init(app_device_t *device)
{
    // 1 配置 读后预处理
    device->post_read = app_bt_post_read;
    // 2 配置 写前预处理
    device->pre_write = app_bt_pre_write;
    // 3 配置相关的蓝牙参数  波特率 、 网络id 网络短地址  网络名
    return app_bt_config_default(device);
}